#pragma once

#include "stdafx.h"
//#include "bbAddon.h"
//#include "ScriptClass.h"

cscriptClass* cscriptCurrentClass = 0;
cscriptClass* cscriptFirstClass = 0;
cscriptClass* cscriptLastClass = 0;

int cscriptClass::_Debug_COUNTcscriptObjs = 0;
int cscriptClass::_CLASS_ID = 0;

cscriptClass::cscriptClass()
{
	_head			=	0;
	_tail			=	0;
	_SizeOfFields	=	0;
	_name			=	"UNKNOWN_CLASS";
	_fieldtypes		=	new int[1];
	_fieldnames		=	new string[1];
	
	_opened			=	false;
	_build			=	false;
	
	if (_HEAD_CLASS==0)
	{
		_HEAD_CLASS = this;
		_prev=0;
	}
	else
	{
		_prev=(cscriptClass*)_TAIL_CLASS;
		_TAIL_CLASS->_next = this;
	};
	_TAIL_CLASS = this;
	_next=0;
	_CLASS_ID++;
	
	if (EnterDef()!=1) SetLastError(15);
	
};

cscriptClass::cscriptClass(const char* Name)
{
	_name			=	Name;
	
	_head			=	0;
	_tail			=	0;
	_name			=	Name;
	_SizeOfFields	=	0;
	_fieldtypes		=	new int[1];
	_fieldnames		=	new string[1];
	
	_opened			=	false;
	_build			=	false;
	
	if (_HEAD_CLASS==0)
	{
		_HEAD_CLASS = this;
		_prev=0;
	}
	else
	{
		_prev=_TAIL_CLASS;
		_TAIL_CLASS->_next=this;
	};
	_TAIL_CLASS = this;
	_next=0;
	_CLASS_ID++;
	
	if (EnterDef()!=1) SetLastError(15);
	
};

cscriptClass::~cscriptClass()
{

	while (_head!=0)
	{
		cscriptObj* temp(_head);
		_head=_head->_next;
		delete temp;
	};
	
	if (this==_HEAD_CLASS)
	{
		if (this==_TAIL_CLASS)
		{
			_HEAD_CLASS=0;
			_TAIL_CLASS=0;
		}
		else
		{
			_HEAD_CLASS=_next;
			_HEAD_CLASS->_prev=0;
		};
	}
	else
	{
		if (this==_TAIL_CLASS)
		{
			_TAIL_CLASS=_prev;
			_TAIL_CLASS->_next=0;
		}
		else
		{
			_prev->_next=_next;
			_next->_prev=_prev;
		};
	};
	_CLASS_ID--;
	
};

bool cscriptClass::_Build()
{
	// To Do : Build class for faster access
	/*
		size_t newSize = _CURDEF_CLASS->_countfields+1;
		const char** newArr = new const char*[newSize];
		memcpy( newArr, arr, size * sizeof(int) );
		
		delete [] _CURDEF_CLASS->_fieldnames;
		_CURDEF_CLASS->_fieldnames= new const char*[_CURDEF_CLASS->_countfields+1];
		_CURDEF_CLASS->_fieldnames[_CURDEF_CLASS->_countfields] = name;
	*/
	_opened	=	false;
	_build	=	true;
	return true;
};

int cscriptClass::EnterDef()
{
	if (_CURDEF_CLASS!=0) return 0;
	_opened			=	true;
	_CURDEF_CLASS	=	this;
	return 1;
};


int cscriptClassLeaveDef()
{
	if (cscriptCurrentClass==0) return 0;
	if (cscriptCurrentClass->_Build()!=true) return 0;
	cscriptCurrentClass=0;
	return 1;
};

cscriptField::cscriptField()
{
	if (cscriptCurrentClass->_fhead==0)
	{
		cscriptCurrentClass->_fhead = this;
		cscriptCurrentClass->_fhead->_prev=0;
	}
	else
	{
		_prev=cscriptCurrentClass->_ftail;
	};
	cscriptCurrentClass->_ftail = this;
	_next=0;
	_class = cscriptCurrentClass;

	cscriptCurrentClass->_countfields++;
	
};

cscriptField::~cscriptField()
{
	
	if (this==_class->_fhead)
	{
		if (this==_class->_ftail)
		{
			_class->_fhead=0;
			_class->_ftail=0;
		}
		else
		{
			_class->_fhead=_next;
			_class->_fhead->_prev=0;
		};
	}
	else
	{
		if (this==_class->_ftail)
		{
			_class->_ftail=_class->_ftail->_prev;
			_class->_ftail->_next=0;
		}
		else
		{
			_next->_prev=_prev;
			_prev->_next=_next;
		};
	};
};

int cscriptClassAddField(const char* signature)
{
	if (cscriptCurrentClass==0) return 0;

	TList* List = StringTokenize(signature," ","%#$");
	TLink* Link = List->_head;
	
	if (Link==0) {DeleteList(List);return 0;};
	if (Link->Next()==0) {DeleteList(List);return 0;};
	
	int typ=0;
	
	/* integer */
	if (Link->Value()=="%")
	{
		typ = SCRIPT_TYPE_INT;
	}
	else
	{
		/* float */
		if (Link->Value()=="#")
		{
			typ = SCRIPT_TYPE_FLOAT;
		}
		else
		{
			/* string */
			if (Link->Value()=="$")
			{
				typ = SCRIPT_TYPE_STRING;
			}
			/* a pointer to an instance of a scriptClass */
			else
			{
				typ = SCRIPT_TYPE_OBJECT;
			};
		};
	};
	
	const char* name = Link->Next()->Value();
	
	cscriptField* newfield = new cscriptField();

	newfield->_name = name;
	newfield->_typedef = typ;

	delete List;
	
	return 1;
};

cscriptClass* cscriptClass::Find (const char* Name)
{
	//if (strcmp(_name,Name)==0)return this;
	//if (this==_TAIL_CLASS)return 0;
	//return _next->Find(Name);
	if (_HEAD_CLASS==0) return 0;
	cscriptClass*Iter=this;
	while (Iter!=0)
	{
		if (Iter->_name.compare(Name)==0) return Iter;
		Iter=Iter->_next;
	}
	return 0;
	
};

void cscriptClass::Unlink(cscriptObj* obj)
{
	if (obj->_class!=this)return;
	
	if (obj==_head)
	{
		if (obj==_tail)
		{
			_head=0;
			_tail=0;
		}
		else
		{
			_head=obj->_next;
			_head->_prev=0;
		};
	}
	else
	{
		if (obj==_tail)
		{
			_tail=_tail->_prev;
			_tail->_next=0;
		}
		else
		{
			obj->_next->_prev=obj->_prev;
			obj->_prev->_next=obj->_next;
		};
	};
	obj->_next=0;
	obj->_prev=0;
};


cscriptObj::cscriptObj(){};

cscriptObj::cscriptObj(cscriptClass*Class)
{
	_class=Class;
	if (Class->_head==0)
	{
		Class->_head=this;
		_prev=0;
	}
	else
	{
		Class->_tail->_next=this;
		_prev=Class->_tail;
	};
	Class->_tail=this;
	_next=0;
	_data = new char[Class->_SizeOfFields];
	cscriptClass::_Debug_COUNTcscriptObjs++;
};

cscriptObj::~cscriptObj(){_Unlink();cscriptClass::_Debug_COUNTcscriptObjs--;};

void cscriptObj::Insert(cscriptObj*obj)
{
	if (_class!=obj->_class) return;
	_Unlink();
	if (obj==_class->_tail)
	{
		_next=0;
		_prev=obj;
		obj->_next=this;
		_class->_tail=this;
	}
	else
	{
		_prev=obj;
		obj->_next->_prev=this;
		_next=obj->_next;
		obj->_next=this;
	};
};

void cscriptObj::Set(const char* Datas, const int FieldID)
{_data = Datas;};

const char* cscriptObj::Get(const int FieldID)
{return _data.c_str();};





/*
BBAEXPint ListInsertBefore(cscriptObj* obj, cscriptObj* before)
{
	if (obj->_list!=before->_list) return 0;
	UncscriptObj(obj);
	cscriptClass* l=before->_list;
	if (before==l->_head)
	{
		obj->_prev=0;
		obj->_next=before;
		before->_prev=obj;
		l->_head=obj;
	}
	else
	{
		obj->_next=before;
		before->_prev->_next=obj;
		obj->_prev=before->_prev;
		before->_prev=obj;
	};

	return 1;
};

BBAEXPint ListAddLast(cscriptClass* list, const char* pValue)
{
	cscriptObj* obj		=	new cscriptObj();
	obj->_data		=	pValue;
	obj->_list		=	list;
	
	if (list->_head==0)
	{
		list->_head	=	obj;
		obj->_prev	=	0;
	}
	else
	{
		list->_tail->_next=obj;
		obj->_prev	=	list->_tail;
	};
	list->_tail		=	obj;
	obj->_next		=	0;
	_Debug_COUNcscriptObjS++;
	return TobbObject(obj);
};

BBAEXPint ListAddFirst(cscriptClass* list, const char* pValue)
{
	cscriptObj* obj		=	new cscriptObj();
	obj->_data		=	pValue;
	obj->_list		=	list;
	
	if (list->_tail==0)
	{
		list->_tail	=	obj;
		obj->_next	=	0;
	}
	else
	{
		list->_head->_prev=obj;
		obj->_next	=	list->_head;
	};
	list->_head		=	obj;
	obj->_prev		=	0;
	_Debug_COUNcscriptObjS++;
	return TobbObject(obj);
};

BBAEXPint ListContains(cscriptClass* list, const char* value)
{
	if (list->_head==0) return 0;
	cscriptObj* l = list->_head;
	while (l!=0)
	{
		if (l->_data.compare(value)==0) return TobbObject(l);
		l=l->_next;
	};
	return 0;
};

BBAEXPcint ListIsEmpty(const cscriptClass* list)	{return (list->_head==0);};

BBAEXPcint FirscscriptObj(const cscriptClass* list)
	{if (list->_head==0){return 0;};return TobbObject(list->_head);};
BBAEXPcint LascscriptObj(const cscriptClass* list)
	{if (list->_head==0){return 0;};return TobbObject(list->_tail);};

BBAEXPcint AftercscriptObj(const cscriptObj* cscriptObj){if (cscriptObj==cscriptObj->_list->_tail){return 0;};return TobbObject(cscriptObj->_next);};
BBAEXPcint BeforecscriptObj(const cscriptObj* cscriptObj){if (cscriptObj==cscriptObj->_list->_head){return 0;};return TobbObject(cscriptObj->_prev);};

BBAEXPint len(const char* a){return strlen(a);};
BBAEXPint cscriptObjCompare(const cscriptObj* l1, const cscriptObj* l2){return l1->_data.compare(l2->_data);};
BBAEXPint StrCompare(const char* a, const char* b){return strcmp(a,b);};
BBAEXPstr cscriptObjValue(const cscriptObj* cscriptObj){return cscriptObj->_data.c_str();};

BBAEXPint SwapcscriptObjs(cscriptObj* l1, cscriptObj* l2)
{
	cscriptClass*l=l1->_list;
	if (l2->_list!=l){return 0;};
	if (l1==l2){return 0;};
	cscriptObj* l1n=l1->_next;
	cscriptObj* l1p=l1->_prev;
	if (l1n==0)
	{
		if(l1p==0)
		{
			return 0;
		}
		else
		{
			UncscriptObj(l1);ListInsertAfter(l1,l2);
			UncscriptObj(l2);ListInsertAfter(l2,l1p);
		};
	}
	else
	{
		UncscriptObj(l1);ListInsertAfter(l1,l2);
		UncscriptObj(l2);ListInsertBefore(l2,l1n);
	};
	return 1;
};

int SorcscriptClassDESC(cscriptClass* list)
{
	bool done=false;

	while (done==false)
	{
		done=true;
		cscriptObj* l1=list->_head->_next;
		cscriptObj* l2;
		
		while (l1!=0)
		{
			l2=l1->_next;
			
			cscriptObj* l3=l1->_prev;
			cscriptObj* l4;
			while (l3!=0)
			{
				l4=l3->_prev;
				if (cscriptObjCompare(l1,l3)>0)
				{
					ListInsertBefore(l1,l3);
					done=false;
				};
				l3=l4;
			};
			l1=l2;
		};
	};
	return 1;
};
int SorcscriptClassASC(cscriptClass* list)
{
	bool done=false;

	while (done==false)
	{
		done=true;
		cscriptObj* l1=list->_head->_next;
		cscriptObj* l2;
		
		while (l1!=0)
		{
			l2=l1->_next;
			
			cscriptObj* l3=l1->_prev;
			cscriptObj* l4;
			while (l3!=0)
			{
				l4=l3->_prev;
				if (cscriptObjCompare(l1,l3)<0)
				{
					ListInsertBefore(l1,l3);
					done=false;
				};
				l3=l4;
			};
			l1=l2;
		};
	};
	return 1;
};

BBAEXPint SorcscriptClass(cscriptClass* list, int sens)
{
	if (list->_head==list->_tail) return 0;
	if (sens<0) return SorcscriptClassDESC(list);
	return SorcscriptClassASC(list);
};

*/




